var PageActions = {
    nextAction: null,
    maxZIndex: 2147483647,
    tryCount: new Date().getTime(),
    /**
     * The first function called when the page initialized.
     * @param {Object} options - passed to the page from
     */
    init: function(options){
        var me = this;
        chrome.extension.sendRequest({
            "action": "getOptions",
        }, function(response){
            me.start(response);
        });
    },
    
    /**
     * Starts the functionality of the extension
     * @param {Object} options
     */
    start: function(options){
        var me = this;
        var count = this.initFlash(options.canLoadOnStartup !== "true").length;
        if (count > 0) {
            __logger__.log("Starting FlashPlus for", count, "objects");
            chrome.extension.sendRequest({
                "action": "setFlashIcon",
                "count": count
            });
            this.setUpListeners();
        }
        else {
            var timeDiff = (new Date().getTime() - this.tryCount);
            var maxTime = parseFloat(options.maxCheckTime, 10) * 1000;
            if (timeDiff < maxTime) {
                __logger__.log("No media found at ", timeDiff, "so will try again till", maxTime, "for", document.location.href);
                window.setTimeout(function(){
                    me.start(options);
                }, 10000);
            }
            else {
                __logger__.log("Exceeded", maxTime, "so not running FlashPlus on ", document.location.href);
            }
        }
    },
    
    /**
     * Iterates over all the flash elements and initialized them by adding a substitute,
     * changing the flash params so that we can draw over it.
     * @param {Object} cannotChangeFlash indicates if we can change the flash or not
     */
    initFlash: function(cannotChangeFlash){
        var result = [];
        var me = this;
        $.each(this.tags, function(i){
            $(this.getElements()).each(function(j){
                var elementSignature = me.getSignatureFromFlash(this);
                elem = $(this);
                if (!cannotChangeFlash) {
                    __logger__.log("Initialising Flash with", elem.attr("id"));
                    elem = me.tags[i].augmentFlash(elem);
                    me.getSubstitute(elem);
                }
                
                result.push({
                    "element": elementSignature,
                    "dimensions": $.extend({
                        "height": elem.height(),
                        "width": elem.width()
                    }, elem.offset()),
                    "frameUrl": (document.location !== (((typeof(top) !== "undefined") ? true : false) && top.location)) && (document.location.href),
                });
            });
        });
        return result;
    },
    
    setUpListeners: function(){
        var me = this;
        var actions = {
            "getPopupAction": function(request){
                if (me.nextAction === null) {
                    var flashComponents = this.initFlash();
                    var commands = [];
                    $.each(me.getCommandList("popup"), function(){
                        commands.push({
                            "command": this,
                            "icon": me.commands[this].icon,
                            "tooltip": me.commands[this].tooltip
                        });
                    });
                    
                    return {
                        "action": "showFlashContent",
                        "data": flashComponents,
                        "tooltip": "Click on any flash element below to change it",
                        "pageDimensions": {
                            "top": window.pageYOffset,
                            "left": window.pageXOffset,
                            "width": document.body.clientWidth,
                            "height": document.body.clientHeight
                        },
                        "commands": commands
                    };
                }
                else {
                    return {
                        "action": "showFlashAction",
                        "data": {
                            "command": me.nextAction.command,
                            "element": me.getSignatureFromFlash(me.nextAction.elem)
                        },
                        "tooltip": me.commands[me.nextAction.command].tooltip,
                        "icon": me.commands[me.nextAction.command].icon
                    }
                }
            },
            
            "executeCommand": function(request){
                var elem = $("#" + request.element.id);
                // This logic is a slower mechanism for locating the node if the web page does not have unique ids
                if (!elem[0] || elem[0].nodeName !== request.element.nodeName) {
                    __logger__.log("Tag and selected element dont match, so searching on tag[id] selector");
                    elem = $([request.element.nodeName, "[id=", request.element.id, "]"].join(""));
                }
                // Confirming if this is the elem we need. Usefel for iFrame cases
                if (elem.attr("flashId") !== request.element.flashId) {
                    return;
                }
                __logger__.log("Executing ", request.command, "on", request);
                me.commands[request.command].action.call(me, elem, request.args);
                
            }
        };
        chrome.extension.onRequest.addListener(function(request, sender, sendResponse){
            try {
                response = actions[request.action].call(me, request);
                sendResponse(response);
            } 
            catch (e) {
                __logger__.log("Error executing command", e, e.stack);
            }
        });
    },
    
    /**
     * Gets the ID of flash. It also sets a unique flashPlusId to differentiate between iFrames
     * @param {Object} elem
     * @param {Object} longVersion
     */
    getSignatureFromFlash: function(elem){
        var elem = $(elem);
        var getOrSet = function(attrName){
            if (!elem.attr(attrName)) {
                elem.attr(attrName, String((new Date()).getTime() + Math.random()).replace(".", "_"));
            }
            return elem.attr(attrName);
        };
        
        return {
            "id": getOrSet("id"),
            "flashId": getOrSet("flashId"),
            "nodeName": elem[0].nodeName
        };
    },
    
    
    /**
     * Adds the tranlucent layer on top of the element where various actions are performend
     * @param {Object} elem
     */
    getHandler: function(elem){
        handler = $("#_HANDLER_" + $(elem).attr("id"));
        if (handler.length === 0) {
            handler = $("<div>", {
                "id": "_HANDLER_" + $(elem).attr("id"),
                "class": "_flashplus_flash-handler"
            }).insertAfter(elem);
            __logger__.log("Adding a new Handler ", handler, "for ", elem);
        }
        return handler;
    },
    
    /**
     * Adds a substitute in place of the element to maintain the page flow
     * @param {Object} elem
     */
    getSubstitute: function(elem){
        if (elem.length === 0) {
            __logger__.log("Could not find Element", elem);
            return;
        }
        // Saving the original position of the element
        var originalPosition = $.extend({
            "height": elem.height(),
            "width": elem.width()
        }, elem.offset());
        
        // Adding an image as the substitute, so that the page structure is maintained.
        var substitute = $("#_SUBSTITUTE_" + $(elem).attr("id"));
        if (substitute.length === 0) {
            substitute = $("<img>", {
                "id": "_SUBSTITUTE_" + $(elem).attr("id")
            }).css({
                "z-index": -1,
                "height": elem.outerHeight(true),
                "width": elem.outerWidth(true),
                "background-image": "url('" + chrome.extension.getURL("images/pattern.png") + "')"
            }).insertBefore(elem).addClass("_flashplus_substitute").css(elem.offset()).css(this.getCSS(elem, ["position", "float"]));
            __logger__.log("Added a substitute for ", elem.position(), " with ", substitute.position());
        }
        
        // Moving the element under the body, and positioning it where it was, originally.
        if (elem.attr("initialized") !== "done") {
            (elem.css("position") !== "absolute") && elem.css("position", "absolute");
            (elem.parent()[0].nodeName !== "BODY") && elem.detach().appendTo(document.body);
            var position = elem.offset();
            // TODO Add the values for padding, border or margin
            elem.css(position).css({
                "z-index": 100000,
                "margin": 0,
                "padding": 0,
                "display": "block",
                "float": "left"
            });
            elem.attr("initialized", "done");
        }
        elem.css(originalPosition);
    },
    
    /**
     * Convinence method to get the CSS properties of an object.
     * @param {Object} elem
     * @param {Object} cssProperties
     */
    getCSS: function(elem, cssProperties){
        var result = {};
        // ["position", "margin-left", "margin-bottom", "margin-right", "margin-top", "float", "padding-left", "padding-right", "padding-top", "padding-bottom", "z-index"
        $.each(cssProperties, function(){
            result[this] = $(elem).css(this.toString());
        });
        return result;
    },
    
    getCommandList: function(context){
        return {
            "popup": ["fullscreen", "find", "download", "shadow"],
            "screenShot": ["shadow", "fullscreen", "removeHandler", "toggleBlock", "popout"]
        }[context];
    },
    
    /**
     * Adds the defination of a new tag that can be handled by this extension
     */
    defineMediaTag: function(tagName, tagDefination){
        this.tags || (this.tags = {});
        this.tags[tagName] = tagDefination;
        if (typeof(tagDefination.selector) === "string") {
            this.tags[tagName].getElements = function(){
                return $(document.body).find(tagDefination.selector);
            }
        }
    }
};

/**
 * Defination of a generic OBJECT tag, without a classID
 */
var objectTagAugment = function(elem){
    var wModeParam = elem.find("param[name=wmode]");
    
    if (wModeParam.attr("value") !== "opaque") {
        var newElem = elem.clone(true);
        var embed = newElem.find("embed");
        embed.replaceWith(newElem.find("embed").clone(true).attr("wmode", "opaque"));
        newElem.find("param[name=wmode]").remove();
        newElem.append("<param name = 'wmode' value= 'opaque'>");
        
        elem.replaceWith(newElem);
        elem = $(newElem);
    }
    return elem;
}
PageActions.defineMediaTag("genericObject", {
    "selector": "object[classid!=clsid:D27CDB6E-AE6D-11cf-96B8-444553540000][classid!=clsid:d27cdb6e-ae6d-11cf-96b8-444553540000][type!=application/x-silverlight-2]",
    "augmentFlash": objectTagAugment
});
PageActions.defineMediaTag("objectTag", {
    "selector": "object[classid=clsid:D27CDB6E-AE6D-11cf-96B8-444553540000], object[classid=clsid:d27cdb6e-ae6d-11cf-96b8-444553540000]",
    "augmentFlash": objectTagAugment
});

PageActions.defineMediaTag("silverlight", {
    "selector": "object[type=application/x-silverlight-2]",
    "augmentFlash": function(elem){
        var windowMode = elem.find("param[name=windowless]");
        if (windowMode.attr("value") !== "true") {
            var newElem = elem.clone(true);
            newElem.find("param[name=windowless]").remove();
            newElem.append("<param name = 'windowless' value= 'true'>");
            elem.replaceWith(newElem);
            elem = $(newElem);
        }
        return elem;
    }
})

PageActions.defineMediaTag("embed", {
    "selector": "embed[type=application/x-shockwave-flash]:not(object embed)",
    "augmentFlash": function(elem){
        if (elem.attr("wmode") !== "opaque") {
            var newElem = elem.clone(true);
            newElem.attr("wmode", "opaque");
            elem.replaceWith(newElem);
            elem = newElem;
        }
        return elem;
    }
});

PageActions.defineMediaTag("canvas,video", {
    "selector": "canvas, video",
    "augmentFlash": function(elem){
        return elem;
    }
});


PageActions.init();
